Imports System, System.Net, System.Net.Sockets
Imports System.Threading
Imports System.Text, System.IO

Public Class Cliente

#Region "Declaraciones"
    'Objetos
    Private MiStream As NetworkStream
    Private MiClienteTCP As TcpClient

    'Variables usadas para las propiedades
    Private _IPRemota As String
    Private _PuertoRemoto As String
    Private _Linea As String
    Private _Number As Integer
    Private _CodOptima As String
    Private _CmdTOSend As Char
    Private _SendingN As Boolean
    Private _tstYellow As Boolean
    Private _LastTryN As Date
    Private _CanReconnect As Boolean = False
    Private _IsConnecting As Boolean
    Private _LastGotData As Date
    Private _GotTarget As Boolean
    'Variables Locales
    Private BufferAcomulado As String
    Dim T As Thread
#End Region

#Region "Constructores"
    Public Sub New(ByVal IP As String, ByVal Port As Long)
        Try
            _IPRemota = IP
            _PuertoRemoto = Port
        Catch Ex As Exception
            RaiseEvent ErrorOcurrido(Me, Ex.Message, "Conectar")
        End Try
    End Sub
#End Region

#Region "Eventos"
    Public Event Conectado(ByVal Sender As Cliente)
    Public Event Desconectado(ByVal Sender As Cliente)
    Public Event DatosRecibidos(ByVal Sender As Cliente, ByVal datos As String)
    Public Event ErrorOcurrido(ByVal Sender As Cliente, ByVal MyEx As String, ByVal Metodo As String)
#End Region

#Region "Metodos Publicos"

    Public Sub BegingConnect()
        If Not T Is Nothing AndAlso T.IsAlive Then
            T.Abort()
            T.Start()
        Else
            T = New Thread(AddressOf Conectar)
            T.Start()
        End If

    End Sub

    Public Sub Conectar()
        Try
            _IsConnecting = True
            Dim NewThread As Thread
            Dim NewThreadConectado As Thread
            MiClienteTCP = New TcpClient()
            MiClienteTCP.Connect(_IPRemota, _PuertoRemoto)
            MiStream = MiClienteTCP.GetStream()

            'Lanzar el evento Conectado en un nuevo Proceso, para no interrumpir
            ' el proceso actual DoRead
            NewThreadConectado = New Thread(AddressOf ProcesaConectado)
            NewThreadConectado.IsBackground = True
            NewThreadConectado.Name = _IPRemota & " Conectado"
            NewThreadConectado.Start()

            NewThread = New Thread(AddressOf DoRead)
            NewThread.IsBackground = True
            NewThread.Name = _IPRemota & " Ciclo Lectura"
            NewThread.Start()
            _IsConnecting = False
        Catch ex As Exception
            _IsConnecting = False
            RaiseEvent ErrorOcurrido(Me, ex.Message, "Conectar")
        End Try
    End Sub

    Public Sub Enviar(ByVal Datos As String)
        'Try
        Dim Buffer() As Byte
        Buffer = Encoding.ASCII.GetBytes(Datos)
        If Not (MiStream Is Nothing) Then
            MiStream.Write(Buffer, 0, Buffer.Length)
        End If
        'Catch ex As Exception
        '    RaiseEvent ErrorOcurrido(Me, ex.Message, "EnviarDatos")
        'End Try
    End Sub

    Public Sub Close()
        Try
            If Not MiClienteTCP Is Nothing Then MiClienteTCP.Close()
        Catch ex As Exception
            RaiseEvent ErrorOcurrido(Me, ex.Message, "Close")
        End Try
    End Sub
#End Region

#Region "Funciones y Procedimientos Privados"
    Private Sub DoRead()
        Dim Buffer() As Byte
        While True
            Try
                If MiClienteTCP Is Nothing Or MiClienteTCP.Client Is Nothing Or MiStream Is Nothing Then Exit While
                Try
                    If (MiClienteTCP.Client.Poll(10, System.Net.Sockets.SelectMode.SelectRead) And (MiClienteTCP.Client.Available = 0)) Then
                        'El Socket esta Desconectado
                        Exit While
                    End If
                Catch ex As Exception

                End Try

                Buffer = New Byte(1024) {}
                Dim Bytes As Int32 = MiStream.Read(Buffer, 0, Buffer.Length)

                If Bytes > 0 Then 'Si los Bytes recibidos es mayor a 0 lanzamos el evento
                    BufferAcomulado = Encoding.ASCII.GetString(Buffer)
                    RaiseEvent DatosRecibidos(Me, BufferAcomulado)
                    'Dim NewThreadDatos As Thread
                    'NewThreadDatos = New Thread(AddressOf ProcesaDatos)
                    'NewThreadDatos.IsBackground = True
                    'NewThreadDatos.Name = _IPRemota & " Datos"
                    'NewThreadDatos.Start()
                End If
            Catch e As Exception
                'RaiseEvent ErrorOcurrido(Me, e.Message, "DoRead")
                Exit While
            End Try
        End While

        Try
            MiClienteTCP.Close() 'Me aseguro de que cierre la coenxion
        Catch ex As Exception

        End Try

        Dim NewThread As Thread
        NewThread = New Thread(AddressOf ProcesaDesconectado)
        NewThread.IsBackground = True
        NewThread.Name = _IPRemota & " Desconectar"
        NewThread.Start()
    End Sub

    'ToDo's:
    '- Lanzar los eventos desde Threads Nuevos

    Sub ProcesaConectado()
        RaiseEvent Conectado(Me)
    End Sub

    Sub ProcesaDesconectado()
        RaiseEvent Desconectado(Me)
    End Sub

    Sub ProcesaDatos()
        RaiseEvent DatosRecibidos(Me, BufferAcomulado)
    End Sub
#End Region

#Region "Propiedades"

    Public Property LastGotData() As Date
        Get
            Return _LastGotData
        End Get
        Set(ByVal Value As Date)
            _LastGotData = Value
        End Set
    End Property

    Public Property GotTarget() As Boolean
        Get
            Return _GotTarget
        End Get
        Set(ByVal value As Boolean)
            _GotTarget = value
        End Set
    End Property
        

    Public ReadOnly Property IsConnecting() As Boolean
        Get
            Return _IsConnecting
        End Get
    End Property

    Public Property CanReconnect() As Boolean
        Get
            Return _CanReconnect
        End Get
        Set(ByVal Value As Boolean)
            _CanReconnect = Value
        End Set
    End Property
    Public Property tstYellow() As Boolean
        Get
            Return _tstYellow
        End Get
        Set(ByVal Value As Boolean)
            _tstYellow = Value
        End Set
    End Property

    Public Property LastTryN() As Date
        Get
            Return _LastTryN
        End Get
        Set(ByVal Value As Date)
            _LastTryN = Value
        End Set
    End Property

    Public Property SendingN() As Boolean
        Get
            Return _SendingN
        End Get
        Set(ByVal Value As Boolean)
            _SendingN = Value
        End Set
    End Property


    Public Property CmdToSend() As Char
        Get
            Return _CmdTOSend
        End Get
        Set(ByVal Value As Char)
            _CmdTOSend = Value
        End Set
    End Property


    Public Property CodOptima() As String
        Get
            Return _CodOptima
        End Get
        Set(ByVal Value As String)
            _CodOptima = Value
        End Set
    End Property

    Public Property Number() As String
        Get
            Return _Number
        End Get
        Set(ByVal Value As String)
            _Number = Value
        End Set
    End Property

    Public Property Linea() As String
        Get
            Return _Linea
        End Get
        Set(ByVal Value As String)
            _Linea = Value
        End Set
    End Property

    Public Property IpRemota() As String
        Get
            IpRemota = _IPRemota
        End Get

        Set(ByVal Value As String)
            _IPRemota = Value
        End Set
    End Property

    Public Property PuertoRemoto() As String
        Get
            PuertoRemoto = _PuertoRemoto
        End Get

        Set(ByVal Value As String)
            _PuertoRemoto = Value
        End Set
    End Property

    Public ReadOnly Property IsConected() As Boolean
        Get
            Dim Value As Boolean
            Try
                If (MiClienteTCP.Client.Poll(10, System.Net.Sockets.SelectMode.SelectRead) And (MiClienteTCP.Client.Available = 0)) Then
                    Value = False
                End If
            Catch ex As Exception

            End Try
            Try

                If Not MiClienteTCP Is Nothing AndAlso Me.MiClienteTCP.Connected Then
                    Return True
                Else
                    Return False
                End If
            Catch ex As Exception

            End Try
            Return False
        End Get
    End Property

#End Region

End Class